package org.apache.ocean.util;

import java.util.concurrent.*;
import java.util.concurrent.locks.*;
import java.util.*;

public class ConcurrentLinkedHashMap<K,V> {
  public LinkedHashMap<K,V> map;
  public final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
  public int maxSize;
  
  public ConcurrentLinkedHashMap(int maxSize) {
    this.maxSize = maxSize;
    map = new LRULinkedHashMap<K,V>();
  }
  
  public ConcurrentLinkedHashMap() {
    map = new LinkedHashMap<K,V>();
  }
  
  public Set<K> keySet() {
  	lock.readLock().lock();
    try {
      return map.keySet();
    } finally {
      lock.readLock().unlock();
    }
  }
  
  public V putIfAbsent(K key, V value) {
    lock.writeLock().lock();
    try {
      V existingValue = map.get(key);
      if (existingValue != null) return existingValue;
      map.put(key, value);
      return value;
    } finally {
      lock.writeLock().unlock();
    }
  }
  
  public Set<Map.Entry<K,V>> entrySet() {
    lock.readLock().lock();
    try {
      return map.entrySet();
    } finally {
      lock.readLock().unlock();
    }
  }
  
  public class LRULinkedHashMap<K,V> extends LinkedHashMap<K,V> {
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
      int size = this.size();
      return size > maxSize;
    }
  }
  
  public void setMaxSize(int maxSize) {
    lock.writeLock().lock();
    try {
      this.maxSize = maxSize;
    } finally {
      lock.writeLock().unlock();
    }
  }
  
  public int size() {
    lock.readLock().lock();
    try {
      return map.size();
    } finally {
      lock.readLock().unlock();
    }
  }
  
  public V get(Object key) {
    lock.readLock().lock();
    try {
      return map.get(key);
    } finally {
      lock.readLock().unlock();
    }
  }
  
  public boolean containsKey(Object key) {
    lock.readLock().lock();
    try {
      return map.containsKey(key);
    } finally {
      lock.readLock().unlock();
    }
  }
  
  public void remove(K key) {
    lock.writeLock().lock();
    try {
      map.remove(key);
    } finally {
      lock.writeLock().unlock();
    }
  }
  
  public void put(K key, V value) {
    lock.writeLock().lock();
    try {
      map.put(key, value);
    } finally {
      lock.writeLock().unlock();
    }
  }
}
